#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <curl/curl.h>

/*
CURLOPT_URL 
设置访问URL

CURLOPT_WRITEFUNCTION，CURLOPT_WRITEDATA
回调函数原型为：size_t function( void *ptr, size_t size, size_t nmemb, void *stream); 
函数将在libcurl接收到数据后被调用，因此函数多做数据保存的功能，如处理下载文件。CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源。

CURLOPT_HEADERFUNCTION，CURLOPT_HEADERDATA
回调函数原型为 size_t function( void *ptr, size_t size,size_t nmemb, void *stream); 
libcurl一旦接收到http 头部数据后将调用该函数。CURLOPT_WRITEDATA 传递指针给libcurl，该指针表明CURLOPT_HEADERFUNCTION 函数的stream指针的来源。

*/
// #define POSTURL    "http://www.xiami.com/member/login"
// #define POSTFIELDS "email=myemail@163.com&password=mypassword&autologin=1&submit=登 录&type="
// #define FILENAME   "/home/zhihui/curlposttest.log"
 
// size_t write_data(void* buffer,size_t size,size_t nmemb,void *stream)
// {
// 	FILE *fptr = (FILE*)stream;
// 	// printf("=======================\n");
// 	// printf("%s",(char *)buffer);
// 	fwrite(buffer,size,nmemb,fptr);
// 	// printf("=======================\n");

// 	return size*nmemb;
// }
 
// int main(int argc,char *argv[])
// {
// 	CURL *curl;
// 	CURLcode res;
// 	FILE* fptr;
// 	struct curl_slist *http_header = NULL;
 
// 	if ((fptr = fopen(FILENAME,"w")) == NULL)
// 	{
// 		fprintf(stderr,"fopen file error:%s\n",FILENAME);
// 		return -1;
// 	}
 
// 	curl = curl_easy_init();
// 	if (!curl)
// 	{
// 		fprintf(stderr,"curl init failed\n");
// 		return -1;
// 	}
 
// 	curl_easy_setopt(curl,CURLOPT_URL,POSTURL); //url地址
// 	curl_easy_setopt(curl,CURLOPT_POSTFIELDS,POSTFIELDS); //post参数
// 	curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data); //对返回的数据进行操作的函数地址
// 	curl_easy_setopt(curl,CURLOPT_WRITEDATA,fptr); //这是write_data的第四个参数值
// 	curl_easy_setopt(curl,CURLOPT_POST,1); //设置问非0表示本次操作为post
// 	curl_easy_setopt(curl,CURLOPT_VERBOSE,1); //打印调试信息
// 	curl_easy_setopt(curl,CURLOPT_HEADER,1); //将响应头信息和相应体一起传给write_data
// 	curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1); //设置为非0,响应头信息location
// 	// curl_easy_setopt(curl,CURLOPT_COOKIEFILE,"/home/zhihui/curlposttest.cookie");
 
// 	res = curl_easy_perform(curl);
 
// 	if (res != CURLE_OK)
// 	{
// 		switch(res)
// 		{
// 			case CURLE_UNSUPPORTED_PROTOCOL:
// 				fprintf(stderr,"不支持的协议,由URL的头部指定\n");
// 			case CURLE_COULDNT_CONNECT:
// 				fprintf(stderr,"不能连接到remote主机或者代理\n");
// 			case CURLE_HTTP_RETURNED_ERROR:
// 				fprintf(stderr,"http返回错误\n");
// 			case CURLE_READ_ERROR:
// 				fprintf(stderr,"读本地文件错误\n");
// 			default:
// 				fprintf(stderr,"返回值:%d\n",res);
// 		}
// 		return -1;
// 	}
// 	fclose(fptr);
 
// 	curl_easy_cleanup(curl);
//     return 0;
// }

#include <iostream>
#include <string>
#include "curl/curl.h"
using namespace std;
 
// wstring AsciiToUnicode(const string& str) 
// {
//     // 预算-缓冲区中宽字节的长度  
//     int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
//     // 给指向缓冲区的指针变量分配内存  
//     wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
//     // 开始向缓冲区转换字节  
//     MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
//     wstring ret_str = pUnicode;
//     free(pUnicode);
//     return ret_str;
// }

// string UnicodeToUtf8(const wstring& wstr) 
// {
//     // 预算-缓冲区中多字节的长度  
//     int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
//     // 给指向缓冲区的指针变量分配内存  
//     char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
//     // 开始向缓冲区转换字节  
//     WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
//     string ret_str = pAssii;
//     free(pAssii);
//     return ret_str;
// }
 
// reply of the requery
size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream)
{
	cout << "----->reply" << endl;
	string *str = (string*)stream;
	cout << *str << endl;
	(*str).append((char*)ptr, size*nmemb);
	return size * nmemb;
}
 
// http GET
CURLcode curl_get_req(const std::string &url, std::string &response)
{
	// init curl
	CURL *curl = curl_easy_init();
	// res code
	CURLcode res;
	if (curl)
	{
		// set params
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl, CURLOPT_HEADER, 1);
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // set transport and time out time
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
		// start req
		res = curl_easy_perform(curl);
	}
	// release curl
	curl_easy_cleanup(curl);
	return res;
}
 
// http POST
CURLcode curl_post_req(const string &url, const string &postParams, string &response)
{
	// init curl
	CURL *curl = curl_easy_init();
	// res code
	CURLcode res;
	//HTTP报文头  
    struct curl_slist* headers = NULL;
	if (curl)
	{
		// set params
		curl_easy_setopt(curl, CURLOPT_POST, 1); // post req
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url
		//构建HTTP报文头  
    //使用模拟的header头设置HTTP请求的头信息
        headers=curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
        
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

		//post请求参数设置，get方法的参数可以在url中体现，post的参数必须在此处设置，参数格式如下"name=daniel&project=curl"
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); // params

		// https请求 不验证证书和hosts
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

		 //传递调用完成时的回调函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
		//回调函数第四个参数
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);

		//关闭中断信号响应，如果是多线程，请将该参数置为1。这个选项用于unix环境下的多线程应用仍然可以使用各种timeout选项，而不会引发信号中断致使程序退出。
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

		 //告诉libcurl在输出请求体时包含头部信息
		curl_easy_setopt(curl, CURLOPT_HEADER, 1);
		//设置连接超时时长（秒）
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
		//请求超时时长（秒）
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
		// start req //执行请求
		res = curl_easy_perform(curl);
	}
	// release curl
	curl_easy_cleanup(curl);
	return res;
}
 
int main()
{
	// global init
	curl_global_init(CURL_GLOBAL_ALL);
 
	// test get requery
	// string getUrlStr = "http://cn.bing.com/images/trending?form=Z9LH";
	// string getResponseStr;
	// CURLcode res = curl_get_req(getUrlStr, getResponseStr);
	// if (res != CURLE_OK)
	// 	cerr << "curl_easy_perform() failed: " + string(curl_easy_strerror(res)) << endl;
	// else
	// 	cout << getResponseStr << endl;
 
	// test post requery
	string postUrlStr = "192.168.1.240:8000/api/token/";
	// string postParams = "username=res&password=123456";
	std::string strJson = "{";
        strJson += "\"username\" : \"rcs\",";
        strJson += "\"password\" : \"123456\"";
        strJson += "}";
	string postResponseStr;
	CURLcode res = curl_post_req(postUrlStr, strJson, postResponseStr);
	if (res != CURLE_OK)
		cerr << "curl_easy_perform() failed: " + string(curl_easy_strerror(res)) << endl;
	else{
		cout << "============" << endl;
		cout << postResponseStr << endl;
	}
		
 
	// global release
	curl_global_cleanup();
	return 0;
}